home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-01-19 | 10.0 KB | 424 lines | [TEXT/MMCC] |
- //
- // CTCPDriver.cp
- //
- // TurboTCP library
- // TCP driver interface class
- //
- // Copyright © 1993-95, FrostByte Design / Eric Scouten
- //
-
- #include "CTCPDriver.h"
-
- #include "CTCPAsyncCall.h"
- #include "CTCPStream.h"
- #include "CTCPResolverCall.h"
-
- #if TurboTCP_UH2
- #include <MacTCP.h>
- #else
- #include <GetMyIPAddr.h>
- #endif
-
- #if TurboTCP_TCL
- #include "CApplication.h"
- #include "CBartender.h"
- #include "CDLOGDirector.h"
- #include "Global.h"
- extern CApplication* gApplication;
- extern CBartender* gBartender;
- #endif
-
-
- //***********************************************************
- //
- // All routines are private interfaces for the use of TurboTCP classes ONLY!
- // They are subject to change in future versions. Be forewarned!
- //
- //***********************************************************
-
-
- //***********************************************************
- //
- // class variable for CTCP driver
- //
-
- CTCPDriver* CTCPDriver::gTCPDriver = nil;
-
-
- //***********************************************************
-
- CTCPDriver::CTCPDriver()
-
- {
-
- // clear variables
-
- hasMacTCP = false;
- hasResolver = false;
- activeResolverCount = myTCPRefNum = 0;
- myIPAddress = 0L;
- gTCPDriver = this;
- activeStreamList.qHead = activeStreamList.qTail = nil;
- activeResolverList.qHead = activeResolverList.qTail = nil;
- asyncQueue.qHead = asyncQueue.qTail = nil;
-
-
- // if on PowerPC, get completion procedure (which is 68K code)
-
- #if TurboTCP_PPC
- CTCPAsyncCall::GetCompletionProc();
- #endif
-
- }
-
-
- //***********************************************************
-
- void CTCPDriver::Dispose()
-
- // Dispose of this object and any lingering TCP async call objects or TCP stream objects.
- // It is CRITICAL that any lingering TCP streams be closed, released, and disposed;
- // otherwise MacTCP is *guaranteed* to crash the machine when the next app launches.
- // If the resolver is open, wait until all resolver queries have been cancelled.
-
- // If at least one second elapses between the start of this routine and the end, flash a
- // dialog box to indicate the reason for the delay.
-
- // The ‘Dispose’ method is retained in C++ because the driver object may need to
- // delay its destruction.
-
- {
- unsigned long startTickCount;
-
- #if TurboTCP_TCL
- CDLOGDirector* theDialog = nil;
- #else
- DialogPtr theDialog = nil;
- #endif
-
-
- // cancel outstanding DNR calls & close resolver
-
- if (hasResolver)
- CTCPResolverCall::CloseResolver();
-
-
- // kill any lingering streams
-
- while (activeStreamList.qHead) {
- CTCPStream* theStream = (CTCPStream*) ((TurboTCPQElem*) activeStreamList.qHead)->qSelfLink;
- theStream->PostponeDispose();
- }
-
-
- // wait for TCP to be done with everything
-
- ::GetDateTime(&startTickCount);
- #if TurboTCP_TCL
- gBartender->DisableMenuBar(); // disable all menus
- #endif
-
- while (activeStreamList.qHead) {
-
- unsigned long theTime;
-
- // do a private event loop & toss up a dialog if it takes more than 2 seconds
-
- ::GetDateTime(&theTime);
- if ((theDialog == nil) && (theTime - startTickCount >= 2)) {
- #if TurboTCP_TCL
- theDialog = new CDLOGDirector(DLOG_TCPDelayedQuit, gApplication);
- theDialog->BeginDialog();
- #else
- theDialog = (DialogPtr) ::GetNewDialog(DLOG_TCPDelayedQuit, nil, (WindowRef) -1);
- ::DrawDialog(theDialog);
- #endif
- }
-
-
- // wait for TCP completions & terminations
-
- #if TurboTCP_TCL
- gApplication->Process1Event();
- #else
- ::SystemTask(); //? should we use WaitNextEvent instead?
- #endif
-
- }
-
-
- // get rid of dialog box (if there was one)
-
- #if TurboTCP_TCL
- TCLForgetObject(theDialog);
- #else
- if (theDialog)
- ::DisposeDialog(theDialog);
- #endif
-
-
- // dispose all the objects
-
- delete this;
-
- }
-
-
- // -- event handling --
-
- //***********************************************************
-
- Boolean CTCPDriver::ProcessOneNetEvent()
-
- // Respond to all delayed TCP notifications, completions, disposals. This routine should be
- // hooked into the application’s event loop or some very frequently called routine.
- // Returns true if there are more asynchronous events in the queue.
-
- {
- void* theAsyncObject;
- TurboTCPQElem* theAsyncEntry;
- CTCPAsyncCall* theAsyncCall;
- CTCPResolverCall* theResolverCall;
- CTCPStream* theStream;
-
-
- // if no events, quit now
-
- if (asyncQueue.qHead == nil)
- return false;
-
-
- // figure out what object caused the notification
-
- theAsyncEntry = (TurboTCPQElem*) asyncQueue.qHead;
- theAsyncObject = theAsyncEntry->qSelfLink;
-
-
- // remove it from the queue (just in case the event processing fails)
-
- ::Dequeue((QElemPtr) theAsyncEntry, &asyncQueue);
-
-
- // process the event
-
- switch (theAsyncEntry->qType) {
- case asyncCall:
- theAsyncCall = (CTCPAsyncCall*) theAsyncObject;
- if (theAsyncCall)
- theAsyncCall ->ProcessCompletion();
- break;
- case resolverCall:
- theResolverCall = (CTCPResolverCall*) theAsyncObject;
- if (theResolverCall)
- theResolverCall->ProcessNotify();
- break;
- case notifyStream:
- theStream = (CTCPStream*) theAsyncObject;
- if (theStream)
- theStream->ProcessNotify();
- break;
- case disposeStream:
- theStream = (CTCPStream*) theAsyncObject;
- if (theStream)
- theStream->Dispose();
- break;
-
- } // switch
-
-
- // tell caller whether there’s another call
-
- return asyncQueue.qHead != nil;
-
- }
-
-
- // -- TCP verification routines --
-
- //***********************************************************
-
- ip_addr CTCPDriver::GetIPAddr() // static method
-
- // Returns the current local IP address, if available. Fails with “noTCPError” error if
- // MacTCP is not installed.
-
- {
- if (!(gTCPDriver->hasMacTCP))
- ThrowOSErr_(noTCPError);
- return gTCPDriver->myIPAddress;
- }
-
-
- //***********************************************************
-
- Boolean CTCPDriver::CheckTCPDriver()
-
- // Check to see if the MacTCP driver is present. Should be done before opening each new
- // connection (built into CTCPStream). If TCP driver is present, updates the current IP
- // address.
-
- // Return true if MacTCP driver is present.
-
- {
- ParamBlockRec theParamBlock;
- unsigned char theName[6] = "\p.IPP"; // MacTCP driver name
-
-
- // if TCP not already confirmed, look for it
-
- if (!hasMacTCP) {
- theParamBlock.ioParam.ioNamePtr = (StringPtr) &theName;
- theParamBlock.ioParam.ioPermssn = fsCurPerm;
- if ((short) ::PBOpenSync(&theParamBlock) == 0) {
- myTCPRefNum = theParamBlock.ioParam.ioRefNum;
- hasMacTCP = true;
- }
- }
-
-
- // If TCP driver available, get the IP address. This is done *each* time a new stream
- // is created because the address might have changed. (This could happen on a machine
- // connected by modem & SLIP, if the user hangs up the modem and re-dials the
- // SLIP server without quitting the program.)
-
- FetchIPAddr();
- return hasMacTCP;
-
- }
-
-
- //***********************************************************
-
- Boolean CTCPDriver::CheckResolver()
-
- // Check to see if the MacTCP DNR code segment is available. If it isn’t, use the
- // OpenResolver call to make it available.
-
- // Returns true if TCP resolver is present.
-
- {
-
- Try_ {
- CTCPResolverCall::OpenResolver();
- hasResolver = true;
- }
- Catch_(err) {
- hasResolver = false;
- DontThrowSame_;
- }
- EndCatch_;
- return hasResolver;
-
- }
-
-
- //***********************************************************
-
- short CTCPDriver::GetTCPRefNum()
-
- // Returns the Device Manager reference number for MacTCP, if available.
- // Fails with “noTCPError” error if not available.
-
- {
- if (!(gTCPDriver->hasMacTCP))
- ThrowOSErr_(noTCPError);
- return gTCPDriver->myTCPRefNum;
- }
-
-
- //***********************************************************
-
- void CTCPDriver::FetchIPAddr()
-
- // Retrieve the local host’s IP address. Does nothing if MacTCP is not available.
- // Stores the new address in the local field myIPAddress, which can be retrieved
- // with the GetIPAddr() method.
-
- {
- struct GetAddrParamBlock theIPParamBlock;
-
- myIPAddress = 0L;
-
- if (hasMacTCP) {
- theIPParamBlock.csCode = ipctlGetAddr;
- theIPParamBlock.ioCRefNum = myTCPRefNum;
- ::PBControlSync((ParmBlkPtr) &theIPParamBlock);
- if (theIPParamBlock.ioResult == noErr)
- myIPAddress = theIPParamBlock.ourAddress;
- }
- }
-
-
- // -- tracking active streams/resolvers --
-
- //***********************************************************
-
- void CTCPDriver::RegisterActiveStream
- (CTCPStream* theStream) // the new stream
-
- // Add a stream object to the list of active TCP streams. The driver object uses this
- // information to ensure that all streams are closed and terminated before the
- // application quits.
-
- {
- ::Enqueue((QElemPtr) &theStream->qActiveStreamEntry, &activeStreamList);
- // activeStreamList->Append(theStream);
- }
-
-
- //***********************************************************
-
- void CTCPDriver::RegisterActiveResolver
- (CTCPResolverCall* theResolver) // the new resolver call
-
- // Add a DNR resolver call to the list of active calls. The driver object uses this
- // information to ensure that all resolver calls are closed and terminated before the
- // application quits.
-
- {
- if (CheckResolverLimit()) // disallow 9th DNR call
- ThrowOSErr_(resolverBusy);
- ::Enqueue((QElemPtr) &theResolver->activeResListEntry, &activeResolverList);
- activeResolverCount++;
- }
-
-
- //***********************************************************
-
- void CTCPDriver::RemoveActiveStream
- (CTCPStream* theStream) // the stream to remove
-
- // Remove a TCP stream from the list of active TCP streams. This message
- // indicates that MacTCP is no longer dependent on the memory structure for
- // the stream.
-
- {
- ::Dequeue((QElemPtr) &theStream->qActiveStreamEntry, &activeStreamList);
- }
-
-
- //***********************************************************
-
- void CTCPDriver::RemoveActiveResolver
- (CTCPResolverCall* theResolver) // the call to remove
-
- // Remove a DNR resolver call from the list of active calls. This message indicates that
- // the MacTCP DNR is no longer dependent on the memory structure for the call.
-
- {
- ::Dequeue((QElemPtr) &theResolver->activeResListEntry, &activeResolverList);
- activeResolverCount--;
- }
-
-
- //***********************************************************
-
- Boolean CTCPDriver::CheckResolverLimit()
-
- // Ensure that the DNR’s limit of 8 calls is not violated.
- // Returns true if too many calls have been issued.
-
- {
- return activeResolverCount >= maxResolverCalls;
- }
-